
jQuery.extend(fn, {
	// Builds initial file list
	initFiles: function() {
		var qtfile = this, files = [];
		qtfile.find(qtfile.options.fileList + ' > ul > li').each(function() {
			files.push(parseJSON(jQuery(this).text()));
		});
		qtfile.resetFiles(files);
	},
	resetFiles: function(files) {

		var qtfile = this, options = qtfile.options,
			classes = options.classes;

		// File list not empty
		if (files.length) {
			var
				$filePanel = qtfile.find(options.fileList);
				// Get the file list ul
				$fileList = $filePanel.children(Ul);

			if ($fileList.size() == 0) {
				$filePanel.removeClass(classes.fileListEmpty);
				$fileList = jQuery(HtmlTagUl)
					.appendTo($filePanel)
					.addClass(classes.fileList);
			}

			// Remove old file items
			$fileList.children(Li).remove();

			// Rebuild each li
			jQuery.each(files, function() {
				qtfile.createFileItem(this).appendTo($fileList);
			});
			qtfile.updateFileList();

		} else {
			// No file in current folder
			qtfile.find(options.fileList)
				.addClass(classes.fileListEmpty)
				.children(Ul).remove();
		}
	},
	createFileItem: function(fileInfo) {
		var 
			qtfile = this,
		// Short cur of class names
			classNames = qtfile.options.classes,

			$fileItem = jQuery(HtmlTagLi)
				.data('info', fileInfo)
				.data(DataKeyFileName, fileInfo.name);

		// File name
		jQuery(HtmlTagSpan)
			.addClass(classNames.fileName)
			.text(fileInfo.name)
			.attr('title', fileInfo.name)
			.prepend(jQuery(HtmlTagSpan).addClass(classNames.fileNameIcon).addClass('icon-file-' + getExt(fileInfo.name)))
			.appendTo($fileItem)
			.click(function() {
				qtfile.showFileDetails(fileInfo);
			});

		// File size
		jQuery(HtmlTagSpan)
			.addClass(classNames.fileSize)
			.text(fileSizeToString(fileInfo.size))
			.appendTo($fileItem);

		var $fileActions = jQuery(HtmlTagSpan)
			.addClass(classNames.fileActions)
			.appendTo($fileItem);

		jQuery(HtmlTagSpan)
			.addClass('file-action-preview')
			.html(qtfile.loc("Preview"))
			.attr('title', qtfile.loc("Preview"))
			.click(function() {
				qtfile.showFileDetails(fileInfo);
			})
			.appendTo($fileActions);

		// Link button
		jQuery(HtmlTagSpan)
			.addClass(classNames.fileActionLink)
			.html(qtfile.loc(TextGetLink))
			.attr('title', qtfile.loc(TextGetLink))
			.click(function() {
				prompt(qtfile.loc(TextLinkIntro), getUrlRoot() + qtfile.getUrl(qtfile.currentFolder, jQuery(this).parent(Span).parent(Li)));
			})
			.appendTo($fileActions);

		// Download button
		jQuery(HtmlTagSpan)
			.addClass(classNames.fileActionDownload)
			.html(qtfile.loc(TextDownload))
			.attr('title', qtfile.loc(TextDownload))
			.click(function() {
				qtfile.downloadFile(qtfile.currentFolder, jQuery(this).parent(Span).parent(Li));
			})
			.appendTo($fileActions);

		// Rename button
		jQuery(HtmlTagSpan)
			.addClass(classNames.fileActionRename)
			.html(qtfile.loc(TextRename))
			.attr('title', qtfile.loc(TextRename))
			.click(function() {
				qtfile.renameFile(qtfile.currentFolder, jQuery(this).parent(Span).parent(Li));
			})
			.appendTo($fileActions);

		// Move button
		jQuery(HtmlTagSpan)
			.addClass(classNames.fileActionMove)
			.html(qtfile.loc(TextMove))
			.attr('title', qtfile.loc(TextMove))
			.click(function() {
				qtfile.moveFileBegin(qtfile.currentFolder, jQuery(this).parent(Span).parent(Li));
			})
			.appendTo($fileActions);

		// Delete button
		jQuery(HtmlTagSpan)
			.addClass(classNames.fileActionDelete)
			.html(qtfile.loc(TextDelete))
			.attr('title', qtfile.loc(TextDelete))
			.click(function() {
				qtfile.deleteFile(qtfile.currentFolder, jQuery(this).parent(Span).parent(Li));
			})
			.appendTo($fileActions);

		return $fileItem;
	},
	initFileDetails: function() {
		var qtfile = this,
			$preview = qtfile.find('.file-preview'),
			loadingHtml = $preview.find('.file-preview-image').html();
		if (!loadingHtml) {
			loadingHtml = 'Loading image...';
		}
		$preview.data('loading', loadingHtml);
			$preview.find('.file-preview-close').click(function() {
			if (!$preview.is(':hidden')) {
				$preview.hide();
			}
		});
	},
	showFileDetails: function(fileInfo) {
		var qtfile = this,
			$preview = qtfile.find('.file-preview');
		$preview.find('.file-preview-name').text(fileInfo.name);
		$preview.find('.file-preview-size').text(fileSizeToString(fileInfo.size));
		$preview.find('.file-preview-content-type').text(fileInfo.contentType);
		var modified = new Date(fileInfo.modified);
		$preview.find('.file-preview-modified').text(modified.toLocaleDateString() + ' ' + modified.toLocaleTimeString());
		
		if (fileInfo.contentType.substr(0, 6) == 'image/') {
			$preview.find('.file-preview-image').html(
				$preview.data('loading')
			).show();


			var img = jQuery('<img alt="' + fileInfo.name + '" src="' + qtfile.getUrl2(qtfile.currentFolder, fileInfo) + '" />')
				.load(function() {
					$preview.find('.file-preview-image').html(img);
				});
		} else {
			$preview.find('.file-preview-image').hide();
		}
			
		if ($preview.is(':hidden')) {
			$preview.show();
		}
	},
	updateFileList: function() {
		var $fileList = this.find(this.options.fileList).children('ul');
		$fileList.children('li:odd').removeClass('even');
		$fileList.children('li:even').addClass('even');
	},
	getUrl2: function($folderItem, fileInfo) {
		var qtfile = this,
			options = qtfile.options,
			filePath = qtfile.combinePath($folderItem.data(DataKeyFolderPath), fileInfo.name),
			url = formatUrl(options.file.download.url, jQuery.extend({}, options.file.download.data, {
				username: options.username,
				path: filePath
			}));

		return url;
	},
	getUrl: function($folderItem, $fileItem) {
		var qtfile = this,
			options = qtfile.options,
			filePath = qtfile.combinePath($folderItem.data(DataKeyFolderPath), $fileItem.data(DataKeyFileName)),
			url = formatUrl(options.file.download.url, jQuery.extend({}, options.file.download.data, {
				username: options.username,
				path: filePath
			}));
		
		return url;
	},
	// Opens the request file in a new window
	downloadFile: function($folderItem, $fileItem) {
		window.open(this.getUrl($folderItem, $fileItem));
	}, // End of downloadFile()		
	// Adds a new file into current folder
	addFile: function(file) {
		var qtfile = this, options = qtfile.options,
			// Get the file list ul
			$fileList = qtfile
				.find(options.fileList)
				.removeClass(options.classes.fileListEmpty)
				.children(Ul);
			
		if ($fileList.size() == 0) {
			$fileList = jQuery(HtmlTagUl)
				.appendTo(qtfile.find(options.fileList))
				.addClass(options.classes.fileList);
		}

		qtfile.createFileItem(file).appendTo($fileList);
		qtfile.updateFileList();
	}, // End of addFile()
	uploadFile: function($fileInput) {
		var qtfile = this, options = qtfile.options,
			classes = options.classes,
			$currentFolder = qtfile.currentFolder;

		// A file is selected
		if ($fileInput.val()) {
			if (qtfile.tryLock(TextFileUploadFileInProgress, TextFileUploadWait)) {

				var frameName =
					options.file.upload.frameName ||
					genRandomId(20);

				// Create a hidden iframe to receive server response
				var $uploadFrame = jQuery('<iframe id="' + frameName + '" name="' + frameName + '"></iframe>')
					.hide()
					.appendTo('body')
					.load(function() {

						var $frame = jQuery(this), data,
							resultText = $frame.contents().find('body').text();

						if (resultText) {
							try {
								data = parseJSON(resultText);
							} catch (err) {
								data = { status: StatusError };
							}

							// File object not returned
							if (data.status) {

								qtfile.unlock(translateFileUploadStatus(data.status),
								qtfile.statusClass(data));
							} else {
								qtfile.addFile(data);

								qtfile.unlock(TextFileUploadSucceed);
							}
						} else {
							qtfile.unlock(TextFileUploadError, classes.statusError);
						}

						setTimeout(function(){
							$frame.attr('src', 'about:blank');
							$frame.remove();
							frameName = $frame = null;
						}, 1);
					});

				// Upload form
				var $uploadFrom =
					jQuery('<form method="post" enctype="multipart/form-data"></form>')
					.attr({
						action: options.file.upload.url,
						target: $uploadFrame.attr('name')
					})
					.appendTo('body');

				// Embed data
				var data = jQuery.extend({ path: $currentFolder.data(DataKeyFolderPath) }, options.file.upload.data);
				for (var k in data) {
					jQuery('<input type="hidden" />')
						.appendTo($uploadFrom)
						.attr({
							name: k,
							value: data[k]
						});
				}

				// Submit form
				$uploadFrom
					.append($fileInput)
					.submit();

				// For new upload file
				$fileInput.appendTo(qtfile.uploadWraper)
				$uploadFrom.remove();

				var uploadChecker = setInterval(
					function() {
						try {

							// Upload frame has not been loaded
							if (frameName) {

								// If invalid page is loaded,
								// this will cause an error in IE or FireFox,
								// and Safari will still fire the load event with empty body.
								// NOTE: If script debug is enabled in IE, an error dialog will popup.
								jQuery('#' + frameName).contents();
							} else {
								clearInterval(uploadChecker);
							}
						} catch (e) {
							clearInterval(uploadChecker);
							jQuery('#' + frameName).remove();
							frameName = null;
							qtfile.unlock(TextFileUploadError, classes.statusError);
						}
					},
				500);

				// For new upload file
				$fileInput.appendTo(qtfile.uploadWraper);
				$uploadFrom.remove();
			}
		}
	},
	// Stores the information for moving file
	moveFileBegin: function($folderItem, $fileItem) {
		var qtfile = this;

		// Lock the file browser
		if (qtfile.tryLock(TextFileMoveInProgress, TextFileMoveWait)) {

			// Store the file path
			qtfile.fileMovingPath = qtfile.combinePath($folderItem.data(DataKeyFolderPath), $fileItem.data(DataKeyFileName));
		}
	}, // End of moveFileBegin()
	// Moves the specified file
	moveFileEnd: function($folderItem) {
		var qtfile = this, options = qtfile.options, fileMovingPath = qtfile.fileMovingPath;

		if (!fileMovingPath)
			return;

		var folderPath = $folderItem.data(DataKeyFolderPath),
			destPath = qtfile.combinePath(folderPath, qtfile.splitPath(fileMovingPath).name);

		// Send request to server
		qtfile.request(
			options.file.move,
			{
				srcPath: fileMovingPath,
				destPath: destPath
			},
			function(data) {
				if (data.succeed) {

					// Remove the file since it has been moved
					qtfile.removeFile(qtfile.splitPath(fileMovingPath).name);
				}
				qtfile.unlock(translateFileMoveStatus(data.status),
					qtfile.statusClass(data));
			},
			function() {
				qtfile.unlock(TextFileMoveError, options.classes.statusError);
			},
			function() { // onComplete
				qtfile.fileMovingPath = null;
			}
		);
	}, // End of moveFileEnd()
	// Renames the specified file
	renameFile: function($folderItem, $fileItem) {
		var qtfile = this, options = qtfile.options;

		// Lock the file browser
		if (qtfile.tryLock(TextFileRenameFileInProgress, TextFileRenameWait)) {

			// Folder path of the file
			var path = $folderItem.data(DataKeyFolderPath);

			var orgFileName = $fileItem.data(DataKeyFileName);

			// Ask for new name
			var newFileName = prompt(TextFileRenameQuestion, getNameOnly(orgFileName));

			if (newFileName && newFileName != orgFileName) {
				
				newFileName = newFileName + '.' + getExt(orgFileName);
				// Test the file name
				if (options.fileName.test(newFileName)) {

					var srcPath = qtfile.combinePath(path, orgFileName);
					var destPath = qtfile.combinePath(path, newFileName);

					// Send request to server
					qtfile.request(
						options.file.move,
						{
							srcPath: srcPath,
							destPath: destPath
						},
						function(data) {
							if (data.succeed) {

								// Update file name
								var fileInfo = $fileItem.data('info');
								fileInfo.name = newFileName;
								qtfile.createFileItem(fileInfo).insertAfter($fileItem);
								$fileItem.remove();
								$fileItem = null;
								qtfile.updateFileList();
							}
							qtfile.unlock(translateFileRenameStatus(data.status), qtfile.statusClass(data));
						},
						function() {
							qtfile.unlock(TextFileRenameError, options.classes.statusError);
						}, null // onComplete
					);

				} else {

					// File name invalid
					alert(TextFileNameInvalid);

					qtfile.unlock();
				} // End if
			} else {
				qtfile.unlock();
			}
		}
	}, // End of renameFile()
	// Deletes the specified file
	deleteFile: function($folderItem, $fileItem) {
		var qtfile = this, options = qtfile.options;

		// Lock the file browser
		if (qtfile.tryLock(TextFileDeleteInProgress, TextFileDeleteWait)) {

			if (!confirm(TextFileDeleteQuestion)) {
				qtfile.unlock();
				return;
			}

			// Folder path of the file
			var folderPath = $folderItem.data(DataKeyFolderPath),
				fileName = $fileItem.data(DataKeyFileName);

			// File path
			var path = qtfile.combinePath(folderPath, fileName);

			// Send request to server
			qtfile.request(
				options.file.del,
				{
					path: path
				},
				function(data) {
					if (data.succeed) {
						qtfile.removeFile($fileItem.data(DataKeyFileName));
					}
					qtfile.unlock(translateFileDeleteStatus(data.status), qtfile.statusClass(data));
				},
				function() {
					qtfile.unlock(TextFileDeleteError, options.classes.statusError);
				}
			);

		}
	}, // End of deleteFile
	// Removes a file from current file list
	removeFile: function(name) {
		var qtfile = this, options = qtfile.options;
		qtfile.find(options.fileList + ' > ul > li').each(function() {
			var $item = jQuery(this);
			if ($item.data(DataKeyFileName) == name) {
				if (qtfile.find(options.fileList + ' li').size() == 1) {
					qtfile.find(options.fileList).addClass(options.classes.fileListEmpty);
				}
				$item.remove();
				qtfile.updateFileList();
			}
		});
	} // End of removeFile
});
